home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 1 / Cream of the Crop 1.iso / KEYBOARD / CMDEDT21.ARJ / EDIT.ASM < prev    next >
Assembly Source File  |  1991-04-30  |  26KB  |  1,058 lines

  1. ; EDIT.ASM
  2. ; (c) 1989, 1990 Ashok P. Nadkarni
  3. ;
  4. ; This module contains the line editing functions of CMDEDIT.
  5.  
  6.     PUBLIC    get_kbd_line
  7.     PUBLIC    auto_recall
  8.     PUBLIC    expand_fnkey
  9.  
  10.     INCLUDE common.inc
  11.     INCLUDE buffers.inc
  12.     INCLUDE ascii.inc
  13.     INCLUDE    BIOS.INC
  14.     INCLUDE    DOS.INC
  15.     INCLUDE    GENERAL.INC
  16.  
  17.  
  18. CSEG    SEGMENT    PARA PUBLIC 'CODE'
  19. CSEG    ENDS
  20.  
  21. DGROUP    GROUP    CSEG
  22.  
  23.     ASSUME    CS:DGROUP, DS:DGROUP, SS:DGROUP, ES:DGROUP
  24.  
  25. CSEG    SEGMENT    PARA PUBLIC 'CODE'
  26.  
  27.     EXTRN    linebuf:BYTE
  28.     EXTRN    lastchar:WORD
  29.     EXTRN    caller_cursor:WORD
  30.     EXTRN    dot:WORD
  31.     EXTRN    edit_mode:BYTE
  32.     EXTRN    omode_cursor:WORD
  33.     EXTRN    sym_stk:WORD
  34.     EXTRN    initial_currow:BYTE
  35.     EXTRN    LINEBUF_END:ABS
  36.     EXTRN    output_newline:PROC
  37.  
  38.  
  39. tempchar db    ?            ;Temporary storage
  40. auto_recall    db    0        ;By default no auto recall
  41. auto_recall_on    db    ?        ;1 if auto-recall in effect,
  42. ;                     else 0
  43. continue_recall db    ?        ;auto-recall state variable
  44. fnkey_tab    db    'S','F',0    ;Used to look for function key
  45. ;                     definitions. 
  46. fnkey_exec_char db    '@'        ;If the last character a fn key
  47. ;                     definition is this, the key is
  48. ;                     executed immediately
  49.  
  50. ; Must be IDENTICAL to the string in CMDCONF.C including the
  51. ; terminating '\0' byte. This must be followed immediately by ctrl_key_defs.
  52. cmdedit_keymap_id db    'CMDEDIT key map',0
  53. ; ctrl_key_redefs is used to allow the cmdconf program to remap the control
  54. ; keys. Each entry corresponds to a control key. It must immediately follow
  55. ; cmdedit_keymap_id.
  56. ctrl_key_redefs LABEL WORD
  57. x    =    0
  58.     REPT    32                ;32 control keys
  59.     DW    x
  60. x    =    x + 1
  61.     ENDM
  62.  
  63.  
  64.     EXTRN    disp_line:PROC
  65.     EXTRN    hist_back:PROC
  66.     EXTRN    hist_fwd:PROC
  67.     EXTRN    hist_bck_match:PROC
  68.     EXTRN    hist_fwd_match:PROC
  69.     EXTRN    remember:PROC
  70.     EXTRN    execute_auto_recall:PROC
  71.     EXTRN    insert_at_dot:PROC
  72.     EXTRN    erase_to_dot:PROC
  73.     EXTRN    isalphnum:PROC
  74.     EXTRN    set_disp_marks:PROC
  75.     EXTRN    bell:PROC
  76.     EXTRN    line_to_scr:PROC
  77.     EXTRN    isspace:PROC
  78.     EXTRN    xlate_lower:PROC
  79.     EXTRN    expand_var:PROC
  80.     EXTRN    ismacsym:PROC
  81.     EXTRN    get_symbol:PROC
  82.     EXTRN    tolower:PROC
  83.     EXTRN    disp_prompt:PROC
  84.     EXTRN    get_curpos:PROC
  85.     
  86. ;number of command keys
  87. NUM_CMD_KEYS    EQU    (cmd_key_jumps-cmd_key_table)/2
  88.  
  89. ;+
  90. ; FUNCTION : get_kbd_line
  91. ;
  92. ;    Gets a line from the user and stores it in linebuf. The length
  93. ;    of the line is stored in global linelen. The name is a misnomer
  94. ;    because the line is from standard input, not necessarily from
  95. ;    the keyboard.
  96. ;
  97. ; Parameters:
  98. ;    None.
  99. ;
  100. ; Returns:
  101. ;    Nothing.
  102. ; Register(s) destroyed:
  103. ;-
  104.  
  105. get_kbd_line    proc    near
  106.     @save    si,di
  107.     mov    al,auto_recall
  108.     mov    auto_recall_on,al    ;Indicate if auto-recall is enabled
  109.     mov    continue_recall,1    ;Init auto-recall memory
  110.  
  111. ; Main editing loop
  112. @get_kbd_line_10:
  113.     mov    al,continue_recall
  114.     and    auto_recall_on,al    ;Indicate if we should keep
  115. ;                     auto-recalling
  116.     mov    continue_recall,0    ;Reset the flag. It will be set
  117. ;                     for the default actions keys.
  118.     call    near ptr disp_line    ;Show current line
  119.     call    near ptr getkey        ;get next key from the user
  120.     mov    si,ax            ;si holds the character
  121.     cmp    ax,32            ;Control character ?
  122.     jge    @get_kbd_line_15    ;No, then check if fn key
  123.     mov    di,si            ;DI used to calculate
  124.     add    di,di            ;  offset into table
  125.     mov    ax,ctrl_key_redefs[di]    ;Mapping of key
  126.     mov    si,ax
  127.     cmp    ax,32            ;Control char ?
  128.     jge    @get_kbd_line_15    ;No, then check if fn key
  129.     mov    di,si            ;DI used to calculate
  130.     add    di,di            ;  offset into table
  131.     jmp    ctrl_key_table[di]    ;Branch according to control char
  132. @get_kbd_line_15:            ;Check if function key
  133.     cmp    ax,256+59        ;>= F1 ?
  134.     jb    @get_kbd_line_20    ;No, then check next table
  135.     cmp    ax,256+68        ;<= F10
  136.     jg    @get_kbd_line_20    ;Not fn key
  137.     jmp    @fn_key            ;Handle the function key
  138. @get_kbd_line_20:
  139.     cmp    ax,256+84        ;>= Shift-F1 ?
  140.     jb    @get_kbd_line_25    ;No, then check next table
  141.     cmp    ax,256+93        ;<= Shift-F10
  142.     jg    @get_kbd_line_25    ;
  143.     jmp    @sfn_key        ;Handle the shifted function key
  144. @get_kbd_line_25:
  145.     mov    cx,NUM_CMD_KEYS        ;size and...
  146.     mov    bx,offset DGROUP:cmd_key_table    ;beginning of jump table
  147. @get_kbd_line_30:            ;Loop begin
  148.     cmp    ax,cs:[bx]        ;Is this the key ?
  149.     je    @get_kbd_line_40    ;Hurrah, found
  150.     inc    bx            ;point to next key
  151.     inc    bx
  152.     loop    @get_kbd_line_30    ;If more keys, repeat
  153.     jmp    short @default_action    ;key not in table
  154. @get_kbd_line_40:            ;Jump to location associated with
  155.     jmp    word ptr cs:[bx+(2*NUM_CMD_KEYS)]    ;key
  156.  
  157. @quote:                    ;Insert next char
  158. ;                     without interpreting it
  159.     call    near ptr  getkey
  160.  
  161. @default_action:            ;Insert the character (in AX)
  162.     call    near ptr store_char
  163.     jc    @get_kbd_line_10    ;No room for char, keep looping
  164.     mov    al,auto_recall_on    ;Are we auto-recalling ?
  165.     or    al,al
  166.     jz    @get_kbd_line_10    ;No
  167.     call    near ptr execute_auto_recall
  168.     jc    @get_kbd_line_10    ;If carry set, no matching
  169. ;                     string in history buffer
  170.     mov    continue_recall,1    ;Else indicate auto-recall is
  171. ;                     still to go on
  172.     jmp    short @get_kbd_line_10
  173.  
  174.  
  175. @char_left:                ;Cursor one char left
  176.     call    near ptr char_left    ;char_left will return to top
  177.     jmp    @get_kbd_line_10
  178. ;                     of editing loop
  179.  
  180. @char_right:                ;Cursor one char right
  181.     call    near ptr char_right    ;char_right will return to top
  182.     jmp    @get_kbd_line_10
  183. ;                     of editing loop
  184.  
  185. @word_left:                ;Cursor one word left
  186.     call    near ptr word_left
  187.     jmp    @get_kbd_line_10
  188.  
  189. @word_right:                ;Cursor one word right
  190.     call    near ptr word_right
  191.     jmp    @get_kbd_line_10
  192.  
  193. @bol:                    ;Beginning of line
  194.     call    near ptr go_bol
  195.     jmp    @get_kbd_line_10
  196.  
  197.  
  198. @eol:                    ;End of line
  199.     call    near ptr go_eol
  200.     jmp    @get_kbd_line_10
  201.  
  202.  
  203. @prev_line:                ;Get previous history line
  204.     mov    ax,offset DGROUP:hist_back
  205. @history_line:
  206.     call    ax
  207.     mov    ax,lastchar
  208.     mov    dot,ax            ;Leave cursor at end of line
  209. @history_search:
  210.     jnc    @history_line_done    ;Line found
  211.     call    near ptr strstk_settop
  212.     call    near ptr bell        ;No line
  213. @history_line_done:
  214.     jmp    @get_kbd_line_10
  215.  
  216. @next_line:                ;Get next history line
  217.     mov    ax,offset DGROUP:hist_fwd
  218.     jmp    short @history_line
  219.  
  220. @search_back:                ;Search back thru history buffer
  221.     mov    ax,offset DGROUP:hist_bck_match
  222. @search:
  223.     mov    di,dot            ;Save current dot
  224.     call    ax
  225.     mov    dot,di            ;Restore it
  226.     jmp    short @history_search
  227.  
  228. @search_forw:                ;Search forward thru history buffer
  229.     mov    ax,offset DGROUP:hist_fwd_match
  230.     jmp    short @search
  231.  
  232.  
  233. @filename:                ;Try to find a matching filename
  234.     call    near ptr match_file
  235.     cmp    auto_recall_on,1    ;Autorecall ongoing?
  236.     je    short @del_eol        ;Yes, then delete to end of line
  237.     jmp    @get_kbd_line_10
  238.  
  239. @del_left:                ;Delete char before cursor
  240.     mov    ax,offset dgroup:char_left
  241.     jmp    short @delete
  242.  
  243. @del_right:                ;Delete char at cursor
  244.     mov    ax,offset dgroup:char_right
  245.     jmp    short @delete
  246.  
  247.  
  248. @del_prev_word:                ;Delete upto word beginning
  249.     mov    ax,offset dgroup:word_left
  250.     jmp    short @delete
  251.  
  252. @del_next_word:                ;Delete to start of next word
  253.     mov    ax,offset dgroup:word_right
  254.     jmp    short @delete
  255.  
  256. @del_bol:                ;Delete to beginning of line
  257.     mov    ax,offset dgroup:go_bol
  258.     jmp    short @delete
  259.  
  260.  
  261. @toggle_insert:
  262.     mov    ax,1
  263.     xor    al,edit_mode        ;Toggle edit mode
  264.     mov    edit_mode,al
  265.     xchg    ax,bx
  266.     add    bx,bx            ;Word offset
  267.     mov    cx,omode_cursor[bx]    ;cx<-cursor shape
  268.     mov    ah,01h            ;Set cursor size function
  269.     IF    TOGGLE_CURSOR
  270.     int    10h            ;BIOS 
  271.     ENDIF
  272.     jmp    @get_kbd_line_10    ;Repeat editing loop
  273.  
  274. @abort_and_store:            ;Erases current line but remembers
  275. ;                     it in the history buffer
  276.     call    near ptr remember
  277. ;    Fall through to erase line
  278. @erase_line:
  279.     call    near ptr go_bol        ;Move dot to beginning of line
  280. ;    fall thru to delete to end of line
  281.  
  282. @del_eol:                ;Delete to end of line
  283.     mov    ax,offset dgroup:go_eol
  284.  
  285. @delete:                ;General purpose delete
  286.     mov    si,dot            ;Remember the dot
  287.     call    ax            ;Move dot to new position
  288.     xchg    si,ax
  289.     call    near ptr erase_to_dot    ;Delete characters between ax and dot
  290.     jmp    @get_kbd_line_10
  291.  
  292. @twiddle:
  293.     mov    si,dot
  294.     cmp    si,lastchar
  295.     jne    @twiddle_10
  296.  
  297.     call    near ptr char_left
  298.     jc    @ignore
  299.     dec    si
  300.  
  301. @twiddle_10:
  302.     call    near ptr char_left
  303.     jc    @ignore
  304.  
  305.     xor    ah,ah
  306.     push    ax
  307.     xchg    si,ax
  308.     call    near ptr erase_to_dot
  309.     call    near ptr char_right
  310.     pop    ax
  311.     jmp    @default_action
  312.  
  313. @autorecall:
  314.     xor    auto_recall,1        ;Toggle auto recall mode
  315.     jmp    @get_kbd_line_10
  316.  
  317. @vars:
  318. ; Expand the variables on the line.
  319.     call    near ptr expand_var
  320.     jmp    @get_kbd_line_10    ;Ignore return status from expand_var
  321.  
  322.  
  323. @inline_back:
  324. @inline_forw:
  325. @ignore:
  326.     jmp    @get_kbd_line_10    ;Ignore the character
  327.  
  328.  
  329. ctrl_key_table    LABEL    WORD
  330.     dw    @ignore        ;NUL or ^@
  331.     dw    @bol        ;^A
  332.     dw    @char_left    ;^B
  333.     dw    @ignore        ;^C
  334.     dw    @del_right    ;^D
  335.     dw    @eol        ;^E
  336.     dw    @char_right    ;^F
  337.     dw    @abort_and_store ;^G
  338.     dw    @del_left    ;^H
  339.     dw    @filename    ;^I
  340.     dw    @vars        ;^J might have to be @ignore in order for input 
  341. ;                 redirection to work properly but try for
  342. ;                 var expansion anyway.
  343.     dw    @del_eol    ;^K
  344.     dw    @del_prev_word    ;^L
  345.     dw    @done_editing    ;^M
  346.     dw    @next_line    ;^N
  347.     dw    @del_eol_exec    ;^O
  348.     dw    @ignore        ;^P - don't use, filtered by get key call ?
  349.     dw    @quote        ;^Q
  350.     dw    @search_back    ;^R
  351.     dw    @ignore        ;^S - don't use, does not work properly
  352.     dw    @twiddle    ;^T
  353.     dw    @prev_line    ;^U
  354.     dw    @search_forw    ;^V
  355.     dw    @del_next_word    ;^W
  356.     dw    @del_bol    ;^X
  357.     dw    @autorecall    ;^Y
  358.     dw    @default_action    ;^Z
  359.     dw    @erase_line    ;^[ or ESC
  360.     dw    @inline_back    ;^\
  361.     dw    @inline_forw    ;^]
  362.     dw    @done_wipeout    ;^^
  363.     dw    @ignore        ;^_
  364.  
  365. cmd_key_table:                ;table of command keys
  366.     dw    127    ;DEL
  367.     dw    327    ;HOME
  368.     dw    328    ;UP
  369.     dw    331    ;LEFT
  370.     dw    333    ;RIGHT
  371.     dw    335    ;END
  372.     dw    336    ;DOWN
  373.     dw    338    ;INS
  374.     dw    339    ;KDEL
  375.     dw    371    ;CTLLEFT
  376.     dw    372    ;CTLRIGHT
  377. cmd_key_jumps:
  378.     dw    @del_left    ;DEL
  379.     dw    @bol        ;HOME
  380.     dw    @prev_line    ;UP
  381.     dw    @char_left    ;LEFT
  382.     dw    @char_right    ;RIGHT
  383.     dw    @eol        ;END
  384.     dw    @next_line    ;DOWN
  385.     dw    @toggle_insert    ;INS
  386.     dw    @del_right    ;KDEL
  387.     dw    @word_left    ;CTLLEFT
  388.     dw    @word_right    ;CTLRIGHT
  389.  
  390.  
  391. @sfn_key:
  392. ; A shifted function key has been struck.
  393. ; (Treat same as an unshifted function key).
  394. @fn_key:
  395. ; A function key has been struck.
  396.     call    near ptr expand_fnkey
  397.     jc    @fn_key_20            ;Error or no expansion
  398.     or    dx,dx                ;Line to be executed
  399. ;                         immediately ?
  400.     je    short @done_editing_2        ;Yes, all done
  401. @fn_key_20:
  402.     jmp    @get_kbd_line_10        ;else keep editing
  403.  
  404. @del_eol_exec:                ;Deletes characters from the dot
  405. ;                     to end of the line and then
  406. ;                     executes the line
  407.     mov    si,dot            ;Remember the dot
  408.     call    go_eol
  409.     xchg    si,ax
  410.     call    near ptr erase_to_dot
  411.     jmp    short @done_editing
  412.  
  413.  
  414. @done_wipeout:
  415. ; The line is executed. However it is not stored in the history buffer and
  416. ; is also removed from the screen (this is a little klugy).
  417.     mov    ax,offset DGROUP:linebuf
  418.     mov    dot,ax
  419.     mov    dx,lastchar
  420.     mov    lastchar,ax            ;Temporarily pretend line
  421. ;                         is empty
  422.     xchg    ax,dx
  423.     push    ax
  424.     call    near ptr set_disp_marks
  425.     call    disp_line
  426.     pop    ax
  427.     mov    lastchar,ax            ;Restore line length
  428.     jmp    short @get_kbd_line_90
  429.  
  430. @done_editing:
  431.     call    near ptr remember    ;Store in history buffer
  432. ;                     Picks up line from global linebuf
  433. @done_editing_2:
  434.     call    near ptr disp_line    ;Necessry for @del_eol_exec,
  435. ;                     might as well do for others
  436.     mov    ax,lastchar
  437.     mov    dot,ax            ;Set dot to end of line
  438.     call    near ptr line_to_scr    ;Set cursor beyond last character
  439.  
  440. @get_kbd_line_90:
  441.     @DispCh CR            ;Do a carraige return because
  442. ;                     some applications like EDLIN
  443. ;                     only do a LF to go to next line
  444. ;    @DispCh LF            ;Go onto next line
  445. ;    all done
  446. @get_kbd_line_99:
  447.     @restore
  448.     ret
  449. get_kbd_line endp
  450.  
  451.  
  452.  
  453. getkey proc near
  454.     @GetKey    0
  455.     mov    ah,0
  456.     or    al,al
  457.     jne    @114        ;not '\0'
  458.     mov    ah,0Bh
  459.     int    21h        ;check if key available
  460.     or    al,al
  461.     jz    @113        ;no character available
  462.     @GetKey    0
  463.     mov    ah,1
  464.     jmp    short @114
  465. @113:
  466.     xor    ax,ax
  467. @114:
  468.     ret
  469. getkey    endp
  470.  
  471.  
  472.  
  473. ;+
  474. ; FUNCTION : expand_fnkey
  475. ;
  476. ;    Inserts the expansion corresponding to a symbol key into the
  477. ;    linebuffer. If the buffer is too small, only as many characters as
  478. ;    possible are inserted and the function returns an error. The
  479. ;    function also returns an error if the symbols is not defined. The
  480. ;    function also updates the displayed line. The function also checks
  481. ;    if the line is to be executed immediately or not, based on the last
  482. ;    character of the fn key expansion.
  483. ;
  484. ; Parameters:
  485. ;    AX    = function key character, must be between (256+59)-(256+68)
  486. ;          function keys and (256+84)-(256+93) for shifted functin keys.
  487. ;
  488. ; Returns:
  489. ;    CF    = 0 if no error, else 1
  490. ;          If CF is 1, then AX is 0 if symbol not found or non-zero
  491. ;          if symbol found but no room in line.
  492. ;    AX    = 1 if symbol was present 
  493. ;          0 if symbol was not found.
  494. ;    DX    = 0 if the line is to be executed immediately
  495. ;          non-0 otherwise
  496. ;          DX is only valid if CF=0 and AX=1
  497. ; Register(s) destroyed:
  498. ;     <TBA>
  499. ;-
  500. expand_fnkey proc near
  501.     @save    si,di
  502.     push    bp
  503.     mov    bp,sp
  504.     sub    sp,LINEBUF_SIZE
  505. exp_buf    equ <byte ptr [bp-LINEBUF_SIZE]>
  506.  
  507.     mov    si,offset DGROUP:fnkey_tab    ;SI->'SFn'
  508.     mov    dx,3                ;DX<-length of string
  509.     mov    di,si
  510.     sub    ax,256+59
  511.     cmp    ax,10                ;Is it a function key
  512.     jnb    @expand_fnkey_10        ;No, shifted function key
  513.     inc    si                ;SI->'Fn'
  514.     dec    dx                ;length of string is 2
  515.     jmp    short @expand_fnkey_15
  516. @expand_fnkey_10:
  517.     sub    ax,84-59
  518. @expand_fnkey_15:
  519.     cmp    ax,9                ;F10 must appear as F0
  520.     jne    @expand_fnkey_20
  521.     mov    al,'0'-'1'
  522. @expand_fnkey_20:
  523.     add    al,'1'
  524.     mov    2[di],al            ;Store in 'SFn' string
  525. ; OK now try and expand the symbol.
  526. ;                         SI->symbol
  527.     mov    ax,LINEBUF_SIZE
  528.     xchg    ax,dx                ;AX<-length of synbol
  529. ;                         DX<-length of expansion buffer
  530.     lea    di,exp_buf
  531.     call    near ptr get_symbol        ;Params SI,AX,DI,DX
  532.     jc    @expand_fnkey_99        ;No symbol (buffer too
  533. ;                         small case not possible).
  534. ;                         AX will be 0 for this case.
  535. ; OK now we have the symbol expansion, so try insert it into the linebuffer.
  536. ;    AX contains length of expansion
  537.     mov    si,di                ;SI->expansion
  538.     add    di,ax
  539.     dec    di                ;DI->last char of expansion
  540.     xor    dx,dx
  541.     mov    dl,byte ptr [di]        
  542.     sub    dl,fnkey_exec_char        ;Is this line to be
  543. ;                         immediately executed
  544.     jne    @expand_fnkey_80        ;No
  545.     dec    ax                ;The last char of expansion
  546. ;                         is a special char. Do not
  547. ;                         include it in the insert
  548. ;                         string 
  549. @expand_fnkey_80:
  550.     push    dx
  551.     call    near ptr insert_at_dot        ;Params SI,AX
  552. ;    pushf                    ;Save CF
  553. ;    call    disp_line
  554. ;    popf                    ;Restore CF
  555.     mov    ax,1                ;AX<-exit code
  556.     pop    dx                ;DX is 0 if line is to be
  557. ;                         executed immediately
  558. @expand_fnkey_99:
  559.     mov    sp,bp
  560.     pop    bp
  561.     @restore
  562.     ret
  563.  
  564. expand_fnkey endp
  565.  
  566.  
  567. ;+
  568. ; FUNCTION : store_char
  569. ;
  570. ;    Stores    the character in AX into the line buffer if max line
  571. ;    length will not be exceeded. Characters may be inserted or
  572. ;    overwrite chars in the buffer depending on the edit mode and whether
  573. ;    auto-recall is on.
  574. ;
  575. ; Parameters:
  576. ;    AX    = character
  577. ;
  578. ; Returns:
  579. ;    CF    = 0 if no error, else 1
  580. ; Register(s) destroyed:
  581. ;     <TBA>
  582. ;-
  583. store_char proc near
  584.     @save    si
  585.     cmp    ax,256            ;char >= 256
  586.     jnb    @store_char_90        ;Ignore if so
  587.     cmp    edit_mode,0        ;1 if insert mode
  588.     je    @store_char_20        ;Jump if overtype mode
  589.     cmp    auto_recall_on,1    ;Is auto-recall on ?
  590.     je    @store_char_20        ;Yes, behave as if in overtype mode
  591.     mov    si,offset dgroup:tempchar ;temporary storage
  592.     mov    [si],al            ;Store char
  593.     mov    ax,1            ;Length of string
  594.     call    near ptr insert_at_dot    ;Insert the character
  595.     jnc    @store_char_99        ;No problemo
  596.     jmp    short @store_char_90    ;No room in buffer
  597. @store_char_20:
  598.     mov    si,dot            ;Current position in line
  599.     cmp    si,LINEBUF_END        ;At line end?
  600.     jae    @store_char_90
  601. ;    Enough room for a char
  602.     mov    [si],al            ;Store the char
  603.     mov    dx,si            ;DX->changed character
  604.     mov    ax,si
  605.     inc    ax            ;AX->char after change
  606.     mov    dot,ax            ;Store it as new dot position
  607.     cmp    si,lastchar        ;Was it end of line ?
  608.     jb    @store_char_30
  609.     mov    lastchar,ax        ;Store new end of line
  610. @store_char_30:
  611.     call    near ptr set_disp_marks    ;ax,dx parameters
  612.     clc                ;Indicate no error
  613.     jmp    short @store_char_99
  614. @store_char_90:
  615.     call    near ptr bell
  616.     stc                ;Indicate error
  617. @store_char_99:
  618.     @restore
  619.     ret
  620. store_char endp
  621.  
  622.  
  623. ;+
  624. ; FUNCTION : word_left
  625. ;
  626. ;    Move one word left.
  627. ;
  628. ; Parameters:
  629. ;    Globals linebuf and dot.
  630. ;
  631. ; Returns:
  632. ;    CF = 1 if dot was at beginning of the line already
  633. ;         0 otherwise.
  634. ; Register(s) destroyed:
  635. ;-
  636. word_left proc near
  637. @word_left_10:
  638.     call    near ptr char_left    ;Move one char left
  639.     jc    @word_left_99        ;Already at beginning of line
  640. @word_left_12:
  641.     ;Loop to backup over non-alphanum
  642.     call    near ptr isalphnum    ;AL alphanumeric?
  643.     jnc    @word_left_15        ;Yes
  644.     call    near ptr char_left    ;One char left.
  645.                     ;AL<-char at dot
  646.     jnc    @word_left_12        ;Not at beginning of line
  647. @word_left_15:                ;Now backup to beginning of word
  648. ;    At this point, dot is always at a alphabetic char or beginning
  649. ;    of the line
  650.     call    near ptr char_left
  651.     jc    @word_left_98        ;Were already at beginning of line
  652.     call    near ptr isalphnum    ;Alphanumeric?
  653.     jnc    @word_left_15        ;Yes, loop back
  654.                     ;Found non-alphanumeric char
  655.     call    near ptr char_right    ;move over one
  656. @word_left_98:
  657.     clc                ;Clear carry flag
  658. @word_left_99:
  659.     ret
  660. word_left endp
  661.  
  662.  
  663.  
  664. ;+
  665. ; FUNCTION : word_right
  666. ;
  667. ;    Move one word right.
  668. ;
  669. ; Parameters:
  670. ;    Globals linebuf and dot.
  671. ;
  672. ; Returns:
  673. ;    Nothing.
  674. ; Register(s) destroyed:
  675. ;-
  676. word_right proc near
  677. @word_right_10:                ;Loop fwd over alphanumerics
  678.     call    near ptr char_right    ;One char right
  679.                     ;AL<-char at dot
  680.     jc    @word_right_99        ;Already at end of line
  681.     call    near ptr isalphnum    ;Is AL alphanumeric ?
  682.     jnc    @word_right_10        ;Yes, loop back
  683. @word_right_15:                ;Now move to beginning of word
  684.     call    near ptr char_right
  685.     jc    @word_right_99        ;Already at end of line
  686.     call    near ptr isalphnum    ;Alphanumeric?
  687.     jc    @word_right_15        ;Not alphanum char, loop back
  688. @word_right_99:
  689.     ret
  690. word_right endp
  691.  
  692.  
  693.  
  694.  
  695. ;+
  696. ; FUNCTION : char_left
  697. ;
  698. ;    Moves the 'dot' one character to the left unless
  699. ;    already at the beginning of the line.
  700. ;
  701. ; Parameters:
  702. ;    Global    dot is current position in the line.
  703. ;
  704. ; Returns:
  705. ;    AL    = char at new dot position.
  706. ;    CF    = 1 if OLD dot was at beginning of line
  707. ;          0 otherwise.
  708. ; Register(s) destroyed:
  709. ;-
  710. char_left proc    near
  711.     @save    si
  712.     mov    ax,dot            ;Current position in line
  713.     cmp    ax,offset dgroup:linebuf
  714.     jne    @char_left_5
  715.     stc                ;Dot already at beginning of line
  716.     jmp    short @char_left_99
  717. @char_left_5:
  718.     dec    ax            ;Move dot left
  719.     mov    dot,ax
  720. @char_left_99:
  721.     xchg    ax,si
  722.     lodsb                ;AL<-char at dot
  723.     @restore
  724.     ret
  725. char_left endp
  726.  
  727.  
  728.  
  729.  
  730.  
  731.  
  732.  
  733. ;+
  734. ; FUNCTION : char_right
  735. ;
  736. ;    Moves the 'dot' one character to the right unless
  737. ;    already at the end of the line.
  738. ;
  739. ; Parameters:
  740. ;    Global    dot is current position in the line.
  741. ;
  742. ; Returns:
  743. ;    AL    = char at new dot position. Undefined if new dot is at
  744. ;          the end of the line.
  745. ;    CF    = 1 if OLD dot was already at end of the line.
  746. ;          0 otherwise.
  747. ; Register(s) destroyed:
  748. ;-
  749. char_right proc    near
  750.     @save    si
  751.     mov    si,dot            ;Current position in line
  752.     mov    ax,lastchar        ;AX->Beyond last char
  753.     dec    ax            ;AX->last char in line
  754.     cmp    ax,si            ;Dot at end ?
  755.     jc    @char_right_99        ;Already at line end
  756.     inc    si            ;Move dot right, CF not affected
  757.     mov    dot,si
  758.     lodsb                ;AL<-char at dot, (undefined if
  759. ;                     dot is now at end of line).
  760. ;    CF    already clear
  761. @char_right_99:
  762.     @restore
  763.     ret
  764. char_right endp
  765.  
  766.  
  767.  
  768. ;+
  769. ; FUNCTION : go_bol
  770. ;
  771. ;    Sets    dot to pint to the beginning of the line
  772. ;
  773. ; Register(s) destroyed: None.
  774. ;-
  775. go_bol    proc    near
  776.     mov    dot,offset dgroup:linebuf
  777.     ret
  778. go_bol    endp
  779.  
  780.  
  781.  
  782. ;+
  783. ; FUNCTION : go_eol
  784. ;
  785. ;    Sets    dot to pint to the end of the line
  786. ;
  787. ; Register(s) destroyed: AX.
  788. ;-
  789. go_eol    proc    near
  790.     mov    ax,lastchar
  791.     mov    dot,ax
  792.     ret
  793. go_eol    endp
  794.  
  795.  
  796.  
  797.  
  798. ;+
  799. ; FUNCTION : match_file
  800. ;
  801. ;    match_file tries to expand the filename to the left of the
  802. ;    cursor. If there are several matching files, the longest common
  803. ;    prefix is placed on the line.  If no characters can be placed
  804. ;    on the line, list the possible matches.
  805. ;
  806. ; Parameters:
  807. ;    None.
  808. ;
  809. ; Returns:
  810. ;    Nothing.
  811. ; Register(s) destroyed:
  812. ;-
  813. match_file proc    near
  814.     @save    si,di
  815.     push    bp
  816.     mov    bp,sp
  817.     sub    sp,64+44+2+2+2+2+2+2    ;Locals
  818. pname        equ    64        ;Storage for entire filename with path
  819. ffblk        equ    pname+44
  820. ffblk_attr     equ    ffblk-15h    ;Attr byte within ffblk
  821. ffblk_name     equ    ffblk-1Eh    ;filename within ffblk
  822. fname        equ    ffblk+2        ;Points to start of filename in name
  823. oldDTAseg     equ    fname+2
  824. oldDTAoff     equ    oldDTAseg+2
  825. lineptr        equ    oldDTAoff+2    ;Pointer to location in linebuf    
  826. remaining    equ    lineptr+2    ;Remembers remaining space in path
  827. breakstate    equ    remaining+2    ;Remembers break state
  828.  
  829.     mov    ax,3300h        ;Get current break state
  830.     int    21h            ;DL<-current break state
  831.     mov    byte ptr [bp-breakstate],dl ;Remember it
  832.     xor    dl,dl
  833.     mov    ax,3301h        ;Disable break check during
  834. ;                     disk i/O
  835.     int    21h
  836.     mov    si,dot            ;Current line position
  837.     mov    cx,63            ;Max length of path
  838. @match_file_10:
  839.     cmp    si,offset dgroup:linebuf
  840.     je    @match_file_51        ;Beginning of line and filename
  841.     dec    si
  842.     mov    al,[si]            ;AL<-next char
  843. @match_file_25:
  844.     call    near ptr isspace
  845.     je    @match_file_50        ;Beginning of filename
  846. @match_file_45:                ;Check for next char if
  847. ;                     pathname not too long
  848.     loop    @match_file_10
  849. @to_match_file_99:
  850.     jmp    @match_file_99        ;Pathname too long, just exit
  851. @match_file_50:
  852.     inc    si
  853. @match_file_51:
  854.     mov    [bp-lineptr],si        ;Save start of path name in linebuf
  855.     mov    ax,63
  856.     sub    ax,cx            ;Length of name
  857.     mov    [bp-remaining],cx    ;remember num bytes left in
  858. ;                     path buffer
  859.     xchg    ax,cx            ;CX<-length of name
  860.     jcxz    @to_match_file_99    ;No name, just exit
  861.  
  862.     call    near ptr @match_file_parse
  863.  
  864. ;    name    contains the filename
  865.     push    es
  866.     @GetDTA                ;Get and save old DTA
  867.     mov    [bp-oldDTAseg],es
  868.     mov    [bp-oldDTAoff],bx
  869.     pop    es
  870. ;
  871.     lea    dx,[bp-ffblk]
  872.     @SetDTA    dx            ;Set DTA to our DTA
  873.  
  874.     lea    dx,[bp-pname]        ;dx->ASCII name
  875.     @GetFirst dx,16            ;Include subdirs in search
  876.     jnc    @match_file_70        ;No error
  877.     call    near ptr bell        ;No files found
  878.     jmp    @match_file_90        ;Restore DTA and exit 
  879.  
  880.  
  881. @match_file_70:                ;At least one file found
  882.     mov    di,[bp-fname]        ;DI->filename portion
  883.     lea    si,[bp-ffblk_name]    ;Name returned by GetFirst
  884. @match_file_71:                ;Copy the file name
  885.     lodsb
  886.     stosb
  887.     test    al,al
  888.     jne    @match_file_71
  889.  
  890.     mov    al,SPACE        ;If file, add a space
  891.     test    byte ptr [bp-ffblk_attr],16 ;Subdirectory?
  892.     je    @match_file_72        ;No
  893.     mov    al,'\'            ;If subdir, add a backslash
  894. @match_file_72:
  895.     mov    byte ptr [di-1],al    ;Add a space or a '\'
  896.     mov    byte ptr [di],0
  897.  
  898. ;    Now hunt for more files. For each file found, keep the longest 
  899. ;    prefix in common so far.
  900.  
  901.     @GetNext            ;Get the next file name
  902.     jc    @match_file_80        ;No more files
  903.  
  904.     mov    di,[bp-fname]        ;DI->start of file name
  905.     lea    si,[bp-ffblk_name]    ;Name returned by GetNext
  906.     mov    cx,13            ;Max Length of field
  907.     repe    cmpsb            ;Compare strings
  908.     mov    byte ptr [di-1],0    ;Terminating null
  909.     jmp    short @match_file_72    ;Try for more files
  910.  
  911. @match_file_80:
  912. ;    Found one or more files, copy the longest common prefix
  913. ;    into the line buffer
  914.     lea    si,[bp-pname]        ;SI->name to be copied
  915.     mov    di,si
  916.     xor    al,al
  917.     mov    cx,64
  918.     repne    scasb            ;Hunt for terminating null
  919.     mov    ax,63
  920.     sub    ax,cx            ;AX<-length of string
  921.  
  922.     mov    dx,dot
  923.     sub    dx,[bp-lineptr]        ;DX<-length of search string
  924.     cmp    ax,dx
  925.     jbe    @match_file_list
  926. ; SI->string, AX is length
  927.     push    ax
  928.     call    near ptr xlate_lower    ;Convert to lowercase
  929.     mov    ax,[bp-lineptr]        ;AX->start of chars to be deleted
  930.     call    near ptr erase_to_dot    ;Delete chars between dot and start
  931.     pop    ax    
  932.     call    near ptr insert_at_dot    ;SI->source, AX == length
  933.  
  934. @match_file_90:
  935.     push    ds
  936.     mov    ds,[bp-oldDTAseg]
  937.     mov    dx,[bp-oldDTAoff]
  938.     @SetDTA    dx            ;Restore DTA
  939.     pop    ds
  940. @match_file_99:
  941. ; Restore previous state of break checking
  942.     mov    dl,byte ptr [bp-breakstate]
  943.     mov    ax,3301h
  944.     int    21h
  945.     mov    sp,bp
  946.     pop    bp
  947.     @restore
  948.     ret
  949.  
  950. @match_file_list:
  951.     mov    si,[bp-lineptr]
  952.     mov    cx,dot
  953.     sub    cx,si
  954.     call    near ptr @match_file_parse
  955.  
  956.     call    near ptr output_newline
  957.     lea    dx,[bp-pname]
  958.     @GetFirst dx,16
  959.  
  960. @match_file_list_10:
  961.     lea    si,[bp-ffblk_name]
  962.     mov    cx,15
  963.  
  964. @match_file_list_20:
  965.     lodsb
  966.     test    al,al
  967.     jz    @match_file_list_30
  968.     call    near ptr tolower
  969.     @DispCh    al
  970.     dec    cx
  971.     jmp    @match_file_list_20
  972.  
  973. @match_file_list_30:
  974.     mov    al,SPACE
  975.     test    byte ptr [bp-ffblk_attr],16 ;Subdirectory?
  976.     je    @match_file_list_40    ;No
  977.     mov    al,'\'            ;If subdir, add a backslash
  978. @match_file_list_40:
  979.     @DispCh al
  980. @match_file_list_50:
  981.     @DispCh SPACE
  982.     loop    @match_file_list_50
  983.     @GetNext
  984.     jnc    @match_file_list_10
  985.  
  986.     call    near ptr get_curpos    ;DX<-current cursor position
  987.     test    dl,dl
  988.     jz    @match_file_list_60
  989.     call    near ptr output_newline
  990. @match_file_list_60:
  991.     call    near ptr disp_prompt
  992.     call    near ptr get_curpos    ;DX<-current cursor position
  993.     mov    initial_currow,dh
  994.     mov    ax,lastchar
  995.     mov    dx,offset DGROUP:linebuf
  996.     call    near ptr set_disp_marks
  997.     call    disp_line            ;Redisplay line
  998.     jmp    @match_file_90
  999. match_file endp
  1000.  
  1001. @match_file_parse proc near
  1002. ;    Copy    filename into ASCIIZ buffer
  1003. ;    SI->first char of filename in path buffer, CX<-length
  1004.     xor    dx,dx            ;Flags
  1005.     lea    di,[bp-pname]        ;OK 'cause SS==DS
  1006.     mov    [bp-fname],di        ;Remember start of filename in
  1007. ;                     path buffer as well (assumed)
  1008. @match_file_p0:
  1009.     lodsb                ;AL<-next char
  1010.     stosb                ;Store it
  1011.     cmp    al,'.'
  1012.     jne    @match_file_p10
  1013.     or    dl,1            ;Set flag to remember file type '.'
  1014.     jmp    short @match_file_p40    ;Check out next character
  1015. @match_file_p10:
  1016.     cmp    al,'\'            ;Directory separator?
  1017.     jne    @match_file_p30
  1018. @match_file_p20:
  1019.     mov    [bp-fname],di        ;Update start of filename in
  1020. ;                     path buffer
  1021.     and    dl,0FEh            ;Forget file type flag
  1022.     jmp    short @match_file_p40
  1023. @match_file_p30:
  1024.     cmp    al,'/'            ;Same thing
  1025.     je    @match_file_p20
  1026.     cmp    al,':'            ;Disk?
  1027.     jne    @match_file_p40
  1028.     and    dl,0FEh            ;Forget file type (shouldn't really 
  1029. ;                     occur)
  1030.     mov    [bp-fname],di        ;Update start of filename in
  1031. ;                     path buffer
  1032.  
  1033. @match_file_p40:
  1034.     loop    @match_file_p0
  1035.  
  1036.     mov    cx,[bp-remaining]    ;CX<-remaining space
  1037.     jcxz    @match_file_p50        ;Only space for terminator
  1038.     mov    al,'*'
  1039.     stosb                ;Attach a '*'
  1040.     cmp    cl,3            ;Enough space for ".*"
  1041.     jb    @match_file_p50
  1042.     and    dl,1            ;Saw a file type ?
  1043.     jne    @match_file_p50        ;Yes, go attach terminator
  1044.     mov    [di],2A2Eh        ;Attach a ".*"
  1045.     inc    di
  1046.     inc    di
  1047. @match_file_p50:
  1048.     xor    al,al            ;AL<-0
  1049.     stosb                ;Terminating 0
  1050.     ret
  1051. @match_file_parse endp
  1052.  
  1053.  
  1054.  
  1055. CSEG    ENDS
  1056.  
  1057.     END
  1058.